﻿using System.Collections.Generic;
using System.Linq;
using CardPlay.Model.GameModel.Actions;

namespace CardPlay.Model.GameModel
{
    public static class ExtensionsToGame
    {
        public static bool IsPlayable(this IGame game)
        {
            var status = game.StateOfPlay;
            return
                status == StateOfPlay.NotStarted ||
                status == StateOfPlay.InProgress ||
                status == StateOfPlay.GameOver;
        }

        public static bool AnyEmptyPilesNamed(this ICardGame cardGame, string pattern)
        {
            return cardGame.PilesNamed(pattern).Any(pile => pile.IsEmpty);
        }

        public static IEnumerable<CardPile> NonEmptyPilesNamed(this ICardGame cardGame, string pattern)
        {
            return cardGame.PilesNamed(pattern).Where(pile => !pile.IsEmpty);
        }

        #region Common post-execute operations

        public static void FlipFaceDownTopCardsInPilesMatching(this CardGame cardGame, string pattern)
        {
            var actions = cardGame.NonEmptyPilesNamed(pattern)
                .Where(pile => !pile.TopCard.IsFaceUp)
                .Select(pile => new FlipCardAction(cardGame, pile.LocationOf(pile.TopCard)));

            foreach (var action in actions)
                cardGame.Execute(action);
        }

        public static void FillFromReserveEmptyPilesMatching(this CardGame cardGame, string pattern)
        {
            cardGame.FillEmptyPilesMatching(pattern, cardGame[CardGame.Reserve]);
        }

        public static void FillFromStockEmptyPilesMatching(this CardGame cardGame, string pattern)
        {
            cardGame.FillEmptyPilesMatching(pattern, cardGame[cardGame.NameOfDealTarget]);
            cardGame.FillEmptyPilesMatching(pattern, cardGame[CardGame.Stock]);
        }

        public static void FillEmptyPilesMatching(this CardGame cardGame, string pattern, CardPile source)
        {
            var emptyPiles = cardGame.PilesNamed(pattern)
                .Where(pile => pile.IsEmpty)
                .Select(pile => new PartLocation(pile.Location.Path, 0));

            var sourceLocation = source.Location;
            sourceLocation.Index = source.Count - 1;

            foreach (var pile in emptyPiles.TakeWhile(pile => sourceLocation.Index >= 0))
            {
                if (!source.CardAt(sourceLocation.Index).IsFaceUp)
                    cardGame.Execute(new FlipCardAction(cardGame, sourceLocation));

                cardGame.Execute(new MoveCardAction(cardGame, sourceLocation, pile));
                --sourceLocation.Index;
            }
        }

        #endregion
    }
}